/**
 *
 * The MIT License
 *
 * Copyright (c) 2008 Board of Trustees, Leland Stanford Jr. University. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.macdadi.ks.client.views;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import org.macdadi.core.client.auth.AuthService;
import org.macdadi.core.client.auth.AuthenticatedUser;
import org.macdadi.core.client.auth.AuthorizationException;
import org.macdadi.core.client.domain.DataService;
import org.macdadi.core.client.domain.DataWriteService;
import org.macdadi.core.client.domain.Option;
import org.macdadi.core.client.domain.ProjectInfo;
import org.macdadi.ks.client.View;
import org.macdadi.ks.client.ViewContainer;

/**
 * @author Ben Suter <ben.suter@gmail.com>
 */
public class Options extends View
{
    protected FlexTable table;
    // TODO: should these fields be part of the View class?
    protected ProjectInfo project;

    protected Button newOptionButton;
    protected boolean allowEdit = false;
    protected boolean allowRemove = false;

    public static ViewInfo init()
    {
        String info = "<p>Designers provide options</p>";

        return new ViewInfo("Options", info)
        {
            public View createInstance(ViewContainer container)
            {
                return new Options(container);
            }

            public String getColor()
            {
                return "#bf2a2a";
            }
        };
    }

    public Options(final ViewContainer container)
    {
        this.container = container;
        project = container.getCurrentProject();

        VerticalPanel mainPanel = new VerticalPanel();
        mainPanel.setStyleName("macdadi-Options");
        mainPanel.setWidth("100%");

        newOptionButton = new Button("Add option");
        final TextBox newOptionInput = new TextBox();
        newOptionInput.setVisibleLength(50);
        HorizontalPanel newOptionPanel = new HorizontalPanel();
        newOptionPanel.add(newOptionInput);
        newOptionPanel.add(newOptionButton);
        mainPanel.add(newOptionPanel);

        table = new FlexTable();
        mainPanel.add(table);

        initWidget(mainPanel);

        newOptionButton.addClickListener(new ClickListener()
        {
            public void onClick(Widget sender)
            {
                String newName = newOptionInput.getText().trim();
                if (newName.length() == 0) {
                    Window.alert("Name may not be blank");
                    return;
                }

                DataWriteService.App.getInstance().createOption(project.getId(), container.getCurrentUser().getId(), newName, container.getCurrentAuthToken(), new AsyncCallback() {
                    public void onFailure(Throwable caught)
                    {
                        GWT.log("Failed to create the new option", caught);
                    }

                    public void onSuccess(Object result)
                    {
                        if ( result != null ) {
                            table.clear();
                            populateTable();
                        }
                    }
                });
                newOptionInput.setText("");
            }
        });
    }

    public void onShow() {
        populateTable();

        AuthenticatedUser user = container.getCurrentUser();

        newOptionButton.setVisible(user.isAuthorizedOperation(project.getId(), AuthService.TARGET_OPTIONS, AuthService.OPERATION_CREATE));
        allowRemove = user.isAuthorizedOperation(project.getId(), AuthService.TARGET_OPTIONS, AuthService.OPERATION_REMOVE);
        allowEdit = user.isAuthorizedOperation(project.getId(), AuthService.TARGET_OPTIONS, AuthService.OPERATION_UPDATE);
    }

    public void onHide() {
        table.clear();
        allowRemove = false;
        allowEdit = false;
    }

    protected void populateTable()
    {
        DataService.App.getInstance().getOptions(project.getId(), container.getCurrentAuthToken(), new AsyncCallback() {
            public void onFailure(Throwable caught)
            {
                GWT.log("Failed to populate the options table", caught);
                if (caught instanceof AuthorizationException) {
                    // TODO: do not use Window.alert for error feedback
                    Window.alert("Please login to view options for " + project.getName());
                }
            }

            public void onSuccess(Object result)
            {
                Option[] options = (Option[]) result;
                for (int i = 0; i < options.length; i++) {
                    addOptionToTable(i, options[i]);
                }
            }
        });
    }

    protected void addOptionToTable(int index, final Option option)
    {
        /**
         * Note: There is a bug in FlexTable whereby the table continues to display
         * part of a row, after the table has been cleared and repopulated without that
         * row. See http://code.google.com/p/google-web-toolkit/issues/detail?id=1766
         * I found that using a Label to wrap plain text solves the problem here.
         */
        table.setWidget(index, 0, new Label(option.getName()));

        if ( allowEdit )
            table.setWidget(index, 1, new Button("Edit", new ClickListener() {
                public void onClick(Widget sender) {
                    editOption(option.getId(), option.getName());
                }
            }));

        if ( allowRemove )
            table.setWidget(index, 2, new Button("Delete", new ClickListener() {
                public void onClick(Widget sender) {
                    removeOption(option.getId());
                }
            }));
    }

    protected void editOption(int optionId, String currentName)
    {
        String newName;
        // TODO: improve prompt for new name, with current name as starting point, and option to cancel
        newName = Window.prompt("Change the name for this option", currentName);
        
        if ( newName == null )
            return; /* User chose "Cancel" */

        if ( newName.equals(currentName) )
            return; /* No change was made */

        DataWriteService.App.getInstance().updateOption(project.getId(), optionId, newName, container.getCurrentAuthToken(), new AsyncCallback() {
            public void onFailure(Throwable caught) {
                GWT.log("Failed to edit the option", caught);
            }

            public void onSuccess(Object result) {
                if (result != null) {
                    table.clear();
                    populateTable();
                }
                // TODO: provide feedback, since did not work
            }
        });
    }

    protected void removeOption(int optionId)
    {
        DataWriteService.App.getInstance().removeOption(project.getId(), optionId, container.getCurrentAuthToken(), new AsyncCallback() {
            public void onFailure(Throwable caught) {
                GWT.log("Failed to remove the option", caught);
            }

            public void onSuccess(Object result) {
                if ( ((Boolean) result).booleanValue() ) {
                    table.clear();
                    populateTable();
                }
                // TODO: provide feedback, since did not work
            }
        });

    }

}